﻿using System;

namespace ScintillaNET;

/// <summary>
/// Represents a line of text in a <see cref="Scintilla" /> control.
/// </summary>
public class Line
{
    #region Fields

    private readonly Scintilla scintilla;

    #endregion Fields

    #region Methods

    /// <summary>
    /// Expands any parent folds to ensure the line is visible.
    /// </summary>
    public void EnsureVisible()
    {
        this.scintilla.DirectMessage(NativeMethods.SCI_ENSUREVISIBLE, new IntPtr(Index));
    }

    //public void ExpandChildren(int level)
    //{
    //}

    /// <summary>
    /// Performs the specified fold action on the current line and all child lines.
    /// </summary>
    /// <param name="action">One of the <see cref="FoldAction" /> enumeration values.</param>
    public void FoldChildren(FoldAction action)
    {
        this.scintilla.DirectMessage(NativeMethods.SCI_FOLDCHILDREN, new IntPtr(Index), new IntPtr((int)action));
    }

    /// <summary>
    /// Performs the specified fold action on the current line.
    /// </summary>
    /// <param name="action">One of the <see cref="FoldAction" /> enumeration values.</param>
    public void FoldLine(FoldAction action)
    {
        this.scintilla.DirectMessage(NativeMethods.SCI_FOLDLINE, new IntPtr(Index), new IntPtr((int)action));
    }

    /// <summary>
    /// Searches for the next line that has a folding level that is less than or equal to <paramref name="level" />
    /// and returns the previous line index.
    /// </summary>
    /// <param name="level">The level of the line to search for. A value of -1 will use the current line <see cref="FoldLevel" />.</param>
    /// <returns>
    /// The zero-based index of the next line that has a <see cref="FoldLevel" /> less than or equal
    /// to <paramref name="level" />. If the current line is a fold point and <paramref name="level"/> is -1 the
    /// index returned is the last line that would be made visible or hidden by toggling the fold state.
    /// </returns>
    public int GetLastChild(int level)
    {
        return this.scintilla.DirectMessage(NativeMethods.SCI_GETLASTCHILD, new IntPtr(Index), new IntPtr(level)).ToInt32();
    }

    /// <summary>
    /// Navigates the caret to the start of the line.
    /// </summary>
    /// <remarks>Any selection is discarded.</remarks>
    public void Goto()
    {
        this.scintilla.DirectMessage(NativeMethods.SCI_GOTOLINE, new IntPtr(Index));
    }

    /// <summary>
    /// Adds the specified <see cref="Marker" /> to the line.
    /// </summary>
    /// <param name="marker">The zero-based index of the marker to add to the line.</param>
    /// <returns>A <see cref="MarkerHandle" /> which can be used to track the line.</returns>
    /// <remarks>This method does not check if the line already contains the <paramref name="marker" />.</remarks>
    public MarkerHandle MarkerAdd(int marker)
    {
        marker = Helpers.Clamp(marker, 0, this.scintilla.Markers.Count - 1);
        IntPtr handle = this.scintilla.DirectMessage(NativeMethods.SCI_MARKERADD, new IntPtr(Index), new IntPtr(marker));
        return new MarkerHandle { Value = handle };
    }

    /// <summary>
    /// Adds one or more markers to the line in a single call using a bit mask.
    /// </summary>
    /// <param name="markerMask">An unsigned 32-bit value with each bit cooresponding to one of the 32 zero-based <see cref="Margin" /> indexes to add.</param>
    public void MarkerAddSet(uint markerMask)
    {
        int mask = unchecked((int)markerMask);
        this.scintilla.DirectMessage(NativeMethods.SCI_MARKERADDSET, new IntPtr(Index), new IntPtr(mask));
    }

    /// <summary>
    /// Removes the specified <see cref="Marker" /> from the line.
    /// </summary>
    /// <param name="marker">The zero-based index of the marker to remove from the line or -1 to delete all markers from the line.</param>
    /// <remarks>If the same marker has been added to the line more than once, this will delete one copy each time it is used.</remarks>
    public void MarkerDelete(int marker)
    {
        marker = Helpers.Clamp(marker, -1, this.scintilla.Markers.Count - 1);
        this.scintilla.DirectMessage(NativeMethods.SCI_MARKERDELETE, new IntPtr(Index), new IntPtr(marker));
    }

    /// <summary>
    /// Returns a bit mask indicating which markers are present on the line.
    /// </summary>
    /// <returns>An unsigned 32-bit value with each bit cooresponding to one of the 32 zero-based <see cref="Marker" /> indexes.</returns>
    public uint MarkerGet()
    {
        int mask = this.scintilla.DirectMessage(NativeMethods.SCI_MARKERGET, new IntPtr(Index)).ToInt32();
        return unchecked((uint)mask);
    }

    /// <summary>
    /// Efficiently searches from the current line forward to the end of the document for the specified markers.
    /// </summary>
    /// <param name="markerMask">An unsigned 32-bit value with each bit cooresponding to one of the 32 zero-based <see cref="Margin" /> indexes.</param>
    /// <returns>If found, the zero-based line index containing one of the markers in <paramref name="markerMask" />; otherwise, -1.</returns>
    /// <remarks>For example, the mask for marker index 10 is 1 shifted left 10 times (1 &lt;&lt; 10).</remarks>
    public int MarkerNext(uint markerMask)
    {
        int mask = unchecked((int)markerMask);
        return this.scintilla.DirectMessage(NativeMethods.SCI_MARKERNEXT, new IntPtr(Index), new IntPtr(mask)).ToInt32();
    }

    /// <summary>
    /// Efficiently searches from the current line backward to the start of the document for the specified markers.
    /// </summary>
    /// <param name="markerMask">An unsigned 32-bit value with each bit cooresponding to one of the 32 zero-based <see cref="Margin" /> indexes.</param>
    /// <returns>If found, the zero-based line index containing one of the markers in <paramref name="markerMask" />; otherwise, -1.</returns>
    /// <remarks>For example, the mask for marker index 10 is 1 shifted left 10 times (1 &lt;&lt; 10).</remarks>
    public int MarkerPrevious(uint markerMask)
    {
        int mask = unchecked((int)markerMask);
        return this.scintilla.DirectMessage(NativeMethods.SCI_MARKERPREVIOUS, new IntPtr(Index), new IntPtr(mask)).ToInt32();
    }

    /// <summary>
    /// Toggles the folding state of the line; expanding or contracting all child lines.
    /// </summary>
    /// <remarks>The line must be set as a <see cref="ScintillaNET.FoldLevelFlags.Header" />.</remarks>
    /// <seealso cref="ToggleFoldShowText"/>
    public void ToggleFold()
    {
        this.scintilla.DirectMessage(NativeMethods.SCI_TOGGLEFOLD, new IntPtr(Index));
    }

    /// <summary>
    /// Toggles the folding state of the line; expanding or contracting all child lines, and specifies the text tag to display to the right of the fold.
    /// </summary>
    /// <param name="text">The text tag to show to the right of the folded text.</param>
    /// <remarks>The display of fold text tags are determined by the <see cref="Scintilla.FoldDisplayTextSetStyle" /> method.</remarks>
    /// <seealso cref="Scintilla.FoldDisplayTextSetStyle" />
    public unsafe void ToggleFoldShowText(string text)
    {
        if (string.IsNullOrEmpty(text))
        {
            this.scintilla.DirectMessage(NativeMethods.SCI_TOGGLEFOLDSHOWTEXT, new IntPtr(Index), IntPtr.Zero);
        }
        else
        {
            byte[] bytes = Helpers.GetBytes(text, this.scintilla.Encoding, zeroTerminated: true);
            fixed (byte* bp = bytes)
                this.scintilla.DirectMessage(NativeMethods.SCI_TOGGLEFOLDSHOWTEXT, new IntPtr(Index), new IntPtr(bp));
        }
    }

    #endregion Methods

    #region Properties

    /// <summary>
    /// Gets the number of annotation lines of text.
    /// </summary>
    /// <returns>The number of annotation lines.</returns>
    public int AnnotationLines
    {
        get
        {
            return this.scintilla.DirectMessage(NativeMethods.SCI_ANNOTATIONGETLINES, new IntPtr(Index)).ToInt32();
        }
    }

    /// <summary>
    /// Gets or sets the style of the annotation text.
    /// </summary>
    /// <returns>
    /// The zero-based index of the annotation text <see cref="Style" /> or 256 when <see cref="AnnotationStyles" />
    /// has been used to set individual character styles.
    /// </returns>
    /// <seealso cref="AnnotationStyles" />
    public int AnnotationStyle
    {
        get
        {
            return this.scintilla.DirectMessage(NativeMethods.SCI_ANNOTATIONGETSTYLE, new IntPtr(Index)).ToInt32();
        }
        set
        {
            value = Helpers.Clamp(value, 0, this.scintilla.Styles.Count - 1);
            this.scintilla.DirectMessage(NativeMethods.SCI_ANNOTATIONSETSTYLE, new IntPtr(Index), new IntPtr(value));
        }
    }

    /// <summary>
    /// Gets or sets an array of style indexes corresponding to each charcter in the <see cref="AnnotationText" />
    /// so that each character may be individually styled.
    /// </summary>
    /// <returns>
    /// An array of <see cref="Style" /> indexes corresponding with each annotation text character or an uninitialized
    /// array when <see cref="AnnotationStyle" /> has been used to set a single style for all characters.
    /// </returns>
    /// <remarks>
    /// <see cref="AnnotationText" /> must be set prior to setting this property.
    /// The <paramref name="value" /> specified should have a length equal to the <see cref="AnnotationText" /> length to properly style all characters.
    /// </remarks>
    /// <seealso cref="AnnotationStyle" />
    public unsafe byte[] AnnotationStyles
    {
        get
        {
            int length = this.scintilla.DirectMessage(NativeMethods.SCI_ANNOTATIONGETTEXT, new IntPtr(Index)).ToInt32();
            if (length == 0)
                return new byte[0];

            byte[] text = new byte[length + 1];
            byte[] styles = new byte[length + 1];

            fixed (byte* textPtr = text)
            fixed (byte* stylePtr = styles)
            {
                this.scintilla.DirectMessage(NativeMethods.SCI_ANNOTATIONGETTEXT, new IntPtr(Index), new IntPtr(textPtr));
                this.scintilla.DirectMessage(NativeMethods.SCI_ANNOTATIONGETSTYLES, new IntPtr(Index), new IntPtr(stylePtr));

                return Helpers.ByteToCharStyles(stylePtr, textPtr, length, this.scintilla.Encoding);
            }
        }
        set
        {
            int length = this.scintilla.DirectMessage(NativeMethods.SCI_ANNOTATIONGETTEXT, new IntPtr(Index)).ToInt32();
            if (length == 0)
                return;

            byte[] text = new byte[length + 1];
            fixed (byte* textPtr = text)
            {
                this.scintilla.DirectMessage(NativeMethods.SCI_ANNOTATIONGETTEXT, new IntPtr(Index), new IntPtr(textPtr));

                byte[] styles = Helpers.CharToByteStyles(value ?? new byte[0], textPtr, length, this.scintilla.Encoding);
                fixed (byte* stylePtr = styles)
                    this.scintilla.DirectMessage(NativeMethods.SCI_ANNOTATIONSETSTYLES, new IntPtr(Index), new IntPtr(stylePtr));
            }
        }
    }

    /// <summary>
    /// Gets or sets the line annotation text.
    /// </summary>
    /// <returns>A String representing the line annotation text.</returns>
    public unsafe string AnnotationText
    {
        get
        {
            int length = this.scintilla.DirectMessage(NativeMethods.SCI_ANNOTATIONGETTEXT, new IntPtr(Index)).ToInt32();
            if (length == 0)
                return string.Empty;

            byte[] bytes = new byte[length + 1];
            fixed (byte* bp = bytes)
            {
                this.scintilla.DirectMessage(NativeMethods.SCI_ANNOTATIONGETTEXT, new IntPtr(Index), new IntPtr(bp));
                return Helpers.GetString(new IntPtr(bp), length, this.scintilla.Encoding);
            }
        }
        set
        {
            // allow empty annotation, set to null to remove
            if (value == null)
            {
                // Scintilla docs suggest that setting to NULL rather than an empty string will free memory
                this.scintilla.DirectMessage(NativeMethods.SCI_ANNOTATIONSETTEXT, new IntPtr(Index), IntPtr.Zero);
            }
            else
            {
                byte[] bytes = Helpers.GetBytes(value, this.scintilla.Encoding, zeroTerminated: true);
                fixed (byte* bp = bytes)
                    this.scintilla.DirectMessage(NativeMethods.SCI_ANNOTATIONSETTEXT, new IntPtr(Index), new IntPtr(bp));
            }
        }
    }

    /// <summary>
    /// Searches from the current line to find the index of the next contracted fold header.
    /// </summary>
    /// <returns>The zero-based line index of the next contracted folder header.</returns>
    /// <remarks>If the current line is contracted the current line index is returned.</remarks>
    public int ContractedFoldNext
    {
        get
        {
            return this.scintilla.DirectMessage(NativeMethods.SCI_CONTRACTEDFOLDNEXT, new IntPtr(Index)).ToInt32();
        }
    }

    /// <summary>
    /// Gets the zero-based index of the line as displayed in a <see cref="Scintilla" /> control
    /// taking into consideration folded (hidden) lines.
    /// </summary>
    /// <returns>The zero-based display line index.</returns>
    /// <seealso cref="Scintilla.DocLineFromVisible" />
    public int DisplayIndex
    {
        get
        {
            return this.scintilla.DirectMessage(NativeMethods.SCI_VISIBLEFROMDOCLINE, new IntPtr(Index)).ToInt32();
        }
    }

    /// <summary>
    /// Gets the zero-based character position in the document where the line ends (exclusive).
    /// </summary>
    /// <returns>The equivalent of <see cref="Position" /> + <see cref="Length" />.</returns>
    public int EndPosition
    {
        get
        {
            return Position + Length;
        }
    }

    /// <summary>
    /// Gets or sets the expanded state (not the visible state) of the line.
    /// </summary>
    /// <remarks>
    /// For toggling the fold state of a single line the <see cref="ToggleFold" /> method should be used.
    /// This property is useful for toggling the state of many folds without updating the display until finished.
    /// </remarks>
    /// <seealso cref="ToggleFold" />
    public bool Expanded
    {
        get
        {
            return this.scintilla.DirectMessage(NativeMethods.SCI_GETFOLDEXPANDED, new IntPtr(Index)) != IntPtr.Zero;
        }
        set
        {
            IntPtr expanded = value ? new IntPtr(1) : IntPtr.Zero;
            this.scintilla.DirectMessage(NativeMethods.SCI_SETFOLDEXPANDED, new IntPtr(Index), expanded);
        }
    }

    /// <summary>
    /// Gets or sets the fold level of the line.
    /// </summary>
    /// <returns>The fold level ranging from 0 to 4095. The default is 1024.</returns>
    public int FoldLevel
    {
        get
        {
            int level = this.scintilla.DirectMessage(NativeMethods.SCI_GETFOLDLEVEL, new IntPtr(Index)).ToInt32();
            return level & NativeMethods.SC_FOLDLEVELNUMBERMASK;
        }
        set
        {
            int bits = (int)FoldLevelFlags;
            bits |= value;

            this.scintilla.DirectMessage(NativeMethods.SCI_SETFOLDLEVEL, new IntPtr(Index), new IntPtr(bits));
        }
    }

    /// <summary>
    /// Gets or sets the fold level flags.
    /// </summary>
    /// <returns>A bitwise combination of the <see cref="FoldLevelFlags" /> enumeration.</returns>
    public FoldLevelFlags FoldLevelFlags
    {
        get
        {
            int flags = this.scintilla.DirectMessage(NativeMethods.SCI_GETFOLDLEVEL, new IntPtr(Index)).ToInt32();
            return (FoldLevelFlags)(flags & ~NativeMethods.SC_FOLDLEVELNUMBERMASK);
        }
        set
        {
            int bits = FoldLevel;
            bits |= (int)value;

            this.scintilla.DirectMessage(NativeMethods.SCI_SETFOLDLEVEL, new IntPtr(Index), new IntPtr(bits));
        }
    }

    /// <summary>
    /// Gets the zero-based line index of the first line before the current line that is marked as
    /// <see cref="ScintillaNET.FoldLevelFlags.Header" /> and has a <see cref="FoldLevel" /> less than the current line.
    /// </summary>
    /// <returns>The zero-based line index of the fold parent if present; otherwise, -1.</returns>
    public int FoldParent
    {
        get
        {
            return this.scintilla.DirectMessage(NativeMethods.SCI_GETFOLDPARENT, new IntPtr(Index)).ToInt32();
        }
    }

    /// <summary>
    /// Gets the height of the line in pixels.
    /// </summary>
    /// <returns>The height in pixels of the line.</returns>
    /// <remarks>Currently all lines are the same height.</remarks>
    public int Height
    {
        get
        {
            return this.scintilla.DirectMessage(NativeMethods.SCI_TEXTHEIGHT, new IntPtr(Index)).ToInt32();
        }
    }

    /// <summary>
    /// Gets the line index.
    /// </summary>
    /// <returns>The zero-based line index within the <see cref="LineCollection" /> that created it.</returns>
    public int Index { get; private set; }

    /// <summary>
    /// Gets the length of the line.
    /// </summary>
    /// <returns>The number of characters in the line including any end of line characters.</returns>
    public int Length
    {
        get
        {
            return this.scintilla.Lines.CharLineLength(Index);
        }
    }

    /// <summary>
    /// Gets or sets the style of the margin text in a <see cref="MarginType.Text" /> or <see cref="MarginType.RightText" /> margin.
    /// </summary>
    /// <returns>
    /// The zero-based index of the margin text <see cref="Style" /> or 256 when <see cref="MarginStyles" />
    /// has been used to set individual character styles.
    /// </returns>
    /// <seealso cref="MarginStyles" />
    public int MarginStyle
    {
        get
        {
            return this.scintilla.DirectMessage(NativeMethods.SCI_MARGINGETSTYLE, new IntPtr(Index)).ToInt32();
        }
        set
        {
            value = Helpers.Clamp(value, 0, this.scintilla.Styles.Count - 1);
            this.scintilla.DirectMessage(NativeMethods.SCI_MARGINSETSTYLE, new IntPtr(Index), new IntPtr(value));
        }
    }

    /// <summary>
    /// Gets or sets an array of style indexes corresponding to each charcter in the <see cref="MarginText" />
    /// so that each character may be individually styled.
    /// </summary>
    /// <returns>
    /// An array of <see cref="Style" /> indexes corresponding with each margin text character or an uninitialized
    /// array when <see cref="MarginStyle" /> has been used to set a single style for all characters.
    /// </returns>
    /// <remarks>
    /// <see cref="MarginText" /> must be set prior to setting this property.
    /// The <paramref name="value" /> specified should have a length equal to the <see cref="MarginText" /> length to properly style all characters.
    /// </remarks>
    /// <seealso cref="MarginStyle" />
    public unsafe byte[] MarginStyles
    {
        get
        {
            int length = this.scintilla.DirectMessage(NativeMethods.SCI_MARGINGETTEXT, new IntPtr(Index)).ToInt32();
            if (length == 0)
                return new byte[0];

            byte[] text = new byte[length + 1];
            byte[] styles = new byte[length + 1];

            fixed (byte* textPtr = text)
            fixed (byte* stylePtr = styles)
            {
                this.scintilla.DirectMessage(NativeMethods.SCI_MARGINGETTEXT, new IntPtr(Index), new IntPtr(textPtr));
                this.scintilla.DirectMessage(NativeMethods.SCI_MARGINGETSTYLES, new IntPtr(Index), new IntPtr(stylePtr));

                return Helpers.ByteToCharStyles(stylePtr, textPtr, length, this.scintilla.Encoding);
            }
        }
        set
        {
            int length = this.scintilla.DirectMessage(NativeMethods.SCI_MARGINGETTEXT, new IntPtr(Index)).ToInt32();
            if (length == 0)
                return;

            byte[] text = new byte[length + 1];
            fixed (byte* textPtr = text)
            {
                this.scintilla.DirectMessage(NativeMethods.SCI_MARGINGETTEXT, new IntPtr(Index), new IntPtr(textPtr));

                byte[] styles = Helpers.CharToByteStyles(value ?? new byte[0], textPtr, length, this.scintilla.Encoding);
                fixed (byte* stylePtr = styles)
                    this.scintilla.DirectMessage(NativeMethods.SCI_MARGINSETSTYLES, new IntPtr(Index), new IntPtr(stylePtr));
            }
        }
    }

    /// <summary>
    /// Gets or sets the text displayed in the line margin when the margin type is
    /// <see cref="MarginType.Text" /> or <see cref="MarginType.RightText" />.
    /// </summary>
    /// <returns>The text displayed in the line margin.</returns>
    public unsafe string MarginText
    {
        get
        {
            int length = this.scintilla.DirectMessage(NativeMethods.SCI_MARGINGETTEXT, new IntPtr(Index)).ToInt32();
            if (length == 0)
                return string.Empty;

            byte[] bytes = new byte[length + 1];
            fixed (byte* bp = bytes)
            {
                this.scintilla.DirectMessage(NativeMethods.SCI_MARGINGETTEXT, new IntPtr(Index), new IntPtr(bp));
                return Helpers.GetString(new IntPtr(bp), length, this.scintilla.Encoding);
            }
        }
        set
        {
            if (string.IsNullOrEmpty(value))
            {
                // Scintilla docs suggest that setting to NULL rather than an empty string will free memory
                this.scintilla.DirectMessage(NativeMethods.SCI_MARGINSETTEXT, new IntPtr(Index), IntPtr.Zero);
            }
            else
            {
                byte[] bytes = Helpers.GetBytes(value, this.scintilla.Encoding, zeroTerminated: true);
                fixed (byte* bp = bytes)
                    this.scintilla.DirectMessage(NativeMethods.SCI_MARGINSETTEXT, new IntPtr(Index), new IntPtr(bp));
            }
        }
    }

    /// <summary>
    /// Gets the zero-based character position in the document where the line begins.
    /// </summary>
    /// <returns>The document position of the first character in the line.</returns>
    public int Position
    {
        get
        {
            return this.scintilla.Lines.CharPositionFromLine(Index);
        }
    }

    /// <summary>
    /// Gets the line text.
    /// </summary>
    /// <returns>A string representing the document line.</returns>
    /// <remarks>The returned text includes any end of line characters.</remarks>
    public unsafe string Text
    {
        get
        {
            IntPtr start = this.scintilla.DirectMessage(NativeMethods.SCI_POSITIONFROMLINE, new IntPtr(Index));
            IntPtr length = this.scintilla.DirectMessage(NativeMethods.SCI_LINELENGTH, new IntPtr(Index));
            IntPtr ptr = this.scintilla.DirectMessage(NativeMethods.SCI_GETRANGEPOINTER, start, length);
            if (ptr == IntPtr.Zero)
                return string.Empty;

            string text = new((sbyte*)ptr, 0, length.ToInt32(), this.scintilla.Encoding);
            return text;
        }
    }

    /// <summary>
    /// Sets or gets the line indentation.
    /// </summary>
    /// <returns>The indentation measured in character columns, which corresponds to the width of space characters.</returns>
    public int Indentation
    {
        get
        {
            return this.scintilla.DirectMessage(NativeMethods.SCI_GETLINEINDENTATION, new IntPtr(Index)).ToInt32();
        }
        set
        {
            this.scintilla.DirectMessage(NativeMethods.SCI_SETLINEINDENTATION, new IntPtr(Index), new IntPtr(value));
        }
    }

    /// <summary>
    /// This returns the position at the end of indentation of a line.
    /// </summary>
    public int IndentPosition
    {
        get
        {
            IntPtr pos = this.scintilla.DirectMessage(NativeMethods.SCI_GETLINEINDENTPOSITION, new IntPtr(Index));
            return this.scintilla.Lines.ByteToCharPosition(pos.ToInt32());
        }
    }

    /// <summary>
    /// Gets a value indicating whether the line is visible.
    /// </summary>
    /// <returns>true if the line is visible; otherwise, false.</returns>
    /// <seealso cref="Scintilla.ShowLines" />
    /// <seealso cref="Scintilla.HideLines" />
    public bool Visible
    {
        get
        {
            return this.scintilla.DirectMessage(NativeMethods.SCI_GETLINEVISIBLE, new IntPtr(Index)) != IntPtr.Zero;
        }
    }

    /// <summary>
    /// Gets the number of display lines this line would occupy when wrapping is enabled.
    /// </summary>
    /// <returns>The number of display lines needed to wrap the current document line.</returns>
    public int WrapCount
    {
        get
        {
            return this.scintilla.DirectMessage(NativeMethods.SCI_WRAPCOUNT, new IntPtr(Index)).ToInt32();
        }
    }

    #endregion Properties

    #region Constructors

    /// <summary>
    /// Initializes a new instance of the <see cref="Line" /> class.
    /// </summary>
    /// <param name="scintilla">The <see cref="Scintilla" /> control that created this line.</param>
    /// <param name="index">The index of this line within the <see cref="LineCollection" /> that created it.</param>
    public Line(Scintilla scintilla, int index)
    {
        this.scintilla = scintilla;
        Index = index;
    }

    #endregion Constructors
}
